package com.zzb.weixin.listener;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import com.zzb.util.DateUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.zzb.weixin.WeiXinMsgFactory;
import com.zzb.weixin.WeiXinService;
import com.zzb.weixin.constant.WXUrlName;
import com.zzb.weixin.exception.WeiXinException;
import com.zzb.weixin.model.msg.basic.EncryptMsg;
import com.zzb.weixin.model.msg.basic.Msg;

/**
 * 抽象会话 此会话声明周期在一个请求响应内。 通过继承类实现各种消息的处理方法
 * 
 * @author marker
 * */
public abstract class ListenerManager {

	/** Document构建类 */
	private static DocumentBuilder getBuilder() throws WeiXinException{
		try {
			return DocumentBuilderFactory.newInstance().newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
			throw new WeiXinException("99999", "");
		}
	}
	private static TransformerFactory getTffactory(){
		return TransformerFactory.newInstance();
	}

	/**
	 * ListenerManager
	 * 
	 */
	protected ListenerManager() {}
	private static ListenerManager listenerManager = DefaultListenerManager.newInstance();
	public static ListenerManager newInstance() {
		return listenerManager;
	}

	/**
	 * 解析微信消息，并传递给对应方法,仅能供未加密消息使用
	 * @param is
	 * @param os
	 * @return
	 * @throws Exception
	 */
	public Msg process(InputStream is, OutputStream os) throws Exception {
		Msg msg = null;
		try {
			System.out.println("进入微信消息解析方法"+ System.currentTimeMillis());
			Document document = getBuilder().parse(is);
			msg = WeiXinMsgFactory.getMsg(document);
			System.out.println("处理消息开始"+ System.currentTimeMillis());
			onMsg(is, os, msg);
			System.out.println("处理消息结束"+ System.currentTimeMillis());
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return msg;
	}
	/**
	 * 解析微信消息，并传递给对应方法
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public Msg process(HttpServletRequest request,HttpServletResponse response) throws Exception {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		OutputStream os = response.getOutputStream();
		InputStream is  = request.getInputStream();

		String timeStamp = (String) request.getAttribute(WXUrlName.TIME_STAMP);
		String nonce = (String) request.getAttribute(WXUrlName.NONCE);
		String msgSignature = (String) request.getAttribute(WXUrlName.MSG_SIGNATURE);
		String encryptType = (String) request.getAttribute(WXUrlName.ENCRYPT_TYPE);
		Msg msg = null;
		try {
			System.out.println("进入微信消息解析方法---加密方法"+ System.currentTimeMillis());
			DocumentBuilder builder = getBuilder();
			//如果需要aes解密,先解密,再调用正常消息处理函数
			if("aes".equals(encryptType)){
				Document document = builder.parse(is);
				EncryptMsg encryptMsg = new EncryptMsg(document);
				String afterDecrpt = WeiXinService.decryptMsg(msgSignature, timeStamp, nonce, encryptMsg);
				StringReader sr = new StringReader(afterDecrpt);
				InputSource isou = new InputSource(sr);
				document = builder.parse(isou);
				System.out.println("解析消息"+ System.currentTimeMillis());
				msg = WeiXinMsgFactory.getMsg(document);
				System.out.println("解析消息结束"+ System.currentTimeMillis());
			}else{
				is  = request.getInputStream();
				Document document = builder.parse(is);
				System.out.println("解析消息"+ System.currentTimeMillis());
				msg = WeiXinMsgFactory.getMsg(document);
				System.out.println("解析消息结束"+ System.currentTimeMillis());
			}
			System.out.println("处理消息开始"+ System.currentTimeMillis());
			onMsg(is,os,msg);
			System.out.println("处理消息结束"+ System.currentTimeMillis());
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return msg;
	}

	/**
	 * 回传消息给微信服务器 只能再接收到微信服务器消息后，才能调用此方法
	 * 
	 * @param msg
	 *            消息对象（支持：文本、音乐、图文）
	 * @throws WeiXinException 
	 * */
	public void callback(InputStream is, OutputStream os,Msg msg) throws WeiXinException {
		Document document = getBuilder().newDocument();
		msg.setDocument(document);
		Element el = msg.write();
		document.appendChild(el);
		try {
			Transformer transformer = getTffactory().newTransformer();
			transformer.transform(new DOMSource(document), new StreamResult(
					new OutputStreamWriter(os, "utf-8")));
		} catch (Exception e) {
			e.printStackTrace();// 保存dom至目输出流
		} finally {
			close(is, os);
		}
	}
	/** 监听器集合 */
	protected List<HandleMessageListener> listeners = new ArrayList<HandleMessageListener>();
	/**
	 * 添加监听器
	 * 
	 * @param handleMassge
	 */
	public void addOnHandleMessageListener(HandleMessageListener handleMassge) {
		listeners.add(handleMassge);
	}

	/**
	 * 移除监听器
	 * */
	public void removeOnHandleMessageListener(HandleMessageListener handleMassge) {
		listeners.remove(handleMassge);
	}
	public void callback(InputStream is, OutputStream os) {
		try {
			os.write("".getBytes());
		} catch (Exception e) {
			e.printStackTrace();// 保存dom至目输出流
		} finally {
			close(is, os);
		}
	}

	/**
	 * 关闭
	 * */
	public void close(InputStream is, OutputStream os) {
		try {
			if (is != null) {
				is.close();
			}
			if (os != null) {
				os.flush();
				os.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 错误消息
	 * 
	 * @param msg
	 */
	public abstract void onMsg(InputStream is, OutputStream os,int errorCode);

	public abstract void onMsg(InputStream is, OutputStream os,Msg msg);
}
